package com.gallop.mq.core.template.handler.registry;

import com.gallop.mq.core.template.handler.DeliveryContext;
import com.gallop.mq.core.template.handler.DeliveryType;
import com.gallop.mq.core.template.handler.MessageDeliveryHandler;
import com.google.common.collect.Maps;
import lombok.Data;
import lombok.Getter;

import java.util.Map;

/**
 * MQ消息监听处理入口。
 * 统一各种MQ的消息监听逻辑注册及调用，
 * {@link com.gallop.mq.MQTemplate}将不同的MQ消息处理方式注册在此即可。
 */
public interface MessageDeliveryHandlerRegistry {

    /**
     * 创建一个MQ消息监听。{@link com.gallop.mq.MQTemplate}具体实现类向MQ注册消息监听时调用此方法，
     * 当消息到达时 {@link DeliveryContext}会随消息一起交给对应类型的{@link MessageDeliveryHandler}处理。
     * 监听器的创建逻辑由{@link RegistryPreprocessor#getListenerCreator()}负责。
     *
     * @param context 消息到达时需要的上下文
     * @param <T>     MQ具体监听类型
     * @return MQ具体的监听
     * @see RegistryPreprocessor#getListenerCreator()
     */
    <T> T createListener(DeliveryContext context);

    /**
     * 触发MQ消息处理
     *
     * @param deliveryContext {@link #createListener(DeliveryContext)}传入的上下文
     * @param args            MQ具体监听类型的参数列表，将会以{@link ListenerArgs}形式封装
     */
    void handleDelivery(DeliveryContext deliveryContext, Object... args);

    /**
     * 初始化：设置消息预处理器
     *
     * @param registryPreprocessor 预处理器
     * @param <T>                  MQ监听器具体的类型
     * @param <M>                  MQ监听收发的消息类型
     */
    <T, M> void setPreprocessor(RegistryPreprocessor<T, M> registryPreprocessor);

    /**
     * 初始化：设置消息处理器
     *
     * @param deliveryType 消息类型
     * @param handler      对应类型的处理器
     */
    void registerHandler(DeliveryType deliveryType, MessageDeliveryHandler handler);


    @Getter
    class InitializerBuilder {

        private RegistryPreprocessor<?, ?> registryPreprocessor;
        private final Map<DeliveryType, MessageDeliveryHandler> handlerMap = Maps.newHashMap();


        public static InitializerBuilder newBuilder() {
            return new InitializerBuilder();
        }

        public <T, M> InitializerBuilder setPreprocessor(RegistryPreprocessor<T, M> preprocessor) {
            this.registryPreprocessor = preprocessor;
            return this;
        }

        public InitializerBuilder registerHandler(DeliveryType deliveryType, MessageDeliveryHandler handler) {
            this.handlerMap.put(deliveryType, handler);
            return this;
        }
    }
}